home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Sample.bin / CLSFractal.java < prev    next >
Text File  |  1998-09-15  |  12KB  |  429 lines

  1. /*
  2.  * @(#)CLSFractal.java    1.5 98/03/23
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
  7.  * modify and redistribute this software in source and binary code form,
  8.  * provided that i) this copyright notice and license appear on all copies of
  9.  * the software; and ii) Licensee does not utilize the software in a manner
  10.  * which is disparaging to Sun.
  11.  *
  12.  * This software is provided "AS IS," without a warranty of any kind. ALL
  13.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
  14.  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
  15.  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
  16.  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  17.  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
  18.  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
  19.  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
  20.  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
  21.  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
  22.  * POSSIBILITY OF SUCH DAMAGES.
  23.  *
  24.  * This software is not designed or intended for use in on-line control of
  25.  * aircraft, air traffic, aircraft navigation or aircraft communications; or in
  26.  * the design, construction, operation or maintenance of any nuclear
  27.  * facility. Licensee represents and warrants that it will not use or
  28.  * redistribute the Software for such purposes.
  29.  */
  30.  
  31. import java.awt.Graphics;
  32. import java.util.Stack;
  33. import java.util.Vector;
  34. import java.awt.event.*;
  35.  
  36. /**
  37.  * A (not-yet) Context sensitive L-System Fractal applet class.
  38.  *
  39.  * The rules for the Context L-system are read from the java.applet.Applet's
  40.  * attributes and then the system is iteratively applied for the
  41.  * given number of levels, possibly drawing each generation as it
  42.  * is generated.  Note that the ContextLSystem class does not yet
  43.  * handle the lContext and rContext attributes, although this
  44.  * class is already designed to parse the '[' and ']' characters
  45.  * typically used in Context sensitive L-Systems.
  46.  *
  47.  * @author     Jim Graham
  48.  * @version     1.1f, 27 Mar 1995
  49.  */
  50. public class CLSFractal 
  51.     extends java.applet.Applet 
  52.     implements Runnable, MouseListener {
  53.     Thread kicker;
  54.     ContextLSystem cls;
  55.     int fractLevel = 1;
  56.     int repaintDelay = 50;
  57.     boolean incrementalUpdates;
  58.     float startAngle = 0;
  59.     float rotAngle = 45;
  60.     float Xmin;
  61.     float Xmax;
  62.     float Ymin;
  63.     float Ymax;
  64.     int border;
  65.     boolean normalizescaling;
  66.  
  67.     public void init() {
  68.     String s;
  69.     cls = new ContextLSystem(this);
  70.     s = getParameter("level");
  71.     if (s != null) fractLevel = Integer.parseInt(s);
  72.     s = getParameter("incremental");
  73.     if (s != null) incrementalUpdates = s.equalsIgnoreCase("true");
  74.     s = getParameter("delay");
  75.     if (s != null) repaintDelay = Integer.parseInt(s);
  76.     s = getParameter("startAngle");
  77.     if (s != null) startAngle = Float.valueOf(s).floatValue();
  78.     s = getParameter("rotAngle");
  79.     if (s != null) rotAngle = Float.valueOf(s).floatValue();
  80.     rotAngle = rotAngle / 360 * 2 * 3.14159265358f;
  81.     s = getParameter("border");
  82.     if (s != null) border = Integer.parseInt(s);
  83.     s = getParameter("normalizescale");
  84.     if (s != null) normalizescaling = s.equalsIgnoreCase("true");
  85.     addMouseListener(this);
  86.     }
  87.  
  88.     public void destroy() {
  89.         removeMouseListener(this);
  90.     }
  91.  
  92.     public void run() {
  93.     Thread me = Thread.currentThread();
  94.     boolean needsRepaint = false;
  95.     while (kicker == me && cls.getLevel() < fractLevel) {
  96.         cls.generate();
  97.         if (kicker == me && incrementalUpdates) {
  98.         repaint();
  99.         try {Thread.sleep(repaintDelay);} catch (InterruptedException e){}
  100.         } else {
  101.         needsRepaint = true;
  102.         }
  103.     }
  104.     if (kicker == me) {
  105.         kicker = null;
  106.         if (needsRepaint) {
  107.         repaint();
  108.         }
  109.     }
  110.     }
  111.  
  112.     public void start() {
  113.     kicker = new Thread(this);
  114.     kicker.start();
  115.     }
  116.  
  117.     public void stop() {
  118.     kicker = null;
  119.     }
  120.  
  121.       /*1.1 event handling */
  122.     public void mouseClicked(MouseEvent e) {
  123.     }
  124.  
  125.     public void mousePressed(MouseEvent e) {
  126.     }
  127.  
  128.     public void mouseReleased(MouseEvent e) {
  129.         cls = new ContextLSystem(this);
  130.         savedPath = null;
  131.         start();
  132.         e.consume();
  133.     }
  134.  
  135.     public void mouseEntered(MouseEvent e) {
  136.     }
  137.  
  138.     public void mouseExited(MouseEvent e) {
  139.     }
  140.       
  141.     String savedPath;
  142.  
  143.     public void paint(Graphics g) {
  144.     String fractalPath = cls.getPath();
  145.     if (fractalPath == null) {
  146.         super.paint(g);
  147.         return;
  148.     }
  149.     if (savedPath == null || !savedPath.equals(fractalPath)) {
  150.         savedPath = fractalPath;
  151.         render(null, fractalPath);
  152.     }
  153.  
  154.     for (int i = 0; i < border; i++) {
  155.         g.draw3DRect(i, i, getSize().width - i * 2, getSize().height - i * 2,false);
  156.     }
  157.     render(g, fractalPath);
  158.     }
  159.  
  160.     void render(Graphics g, String path) {
  161.     Stack turtleStack = new Stack();
  162.     CLSTurtle turtle;
  163.  
  164.     if (g == null) {
  165.         Xmin = 1E20f;
  166.         Ymin = 1E20f;
  167.         Xmax = -1E20f;
  168.         Ymax = -1E20f;
  169.         turtle = new CLSTurtle(startAngle, 0, 0, 0, 0, 1, 1);
  170.     } else {
  171.         float frwidth = Xmax - Xmin;
  172.         if (frwidth == 0)
  173.         frwidth = 1;
  174.         float frheight = Ymax - Ymin;
  175.         if (frheight == 0)
  176.         frheight = 1;
  177.         float xscale = (getSize().width - border * 2 - 1) / frwidth;
  178.         float yscale = (getSize().height - border * 2 - 1) / frheight;
  179.         int xoff = border;
  180.         int yoff = border;
  181.         if (normalizescaling) {
  182.         if (xscale < yscale) {
  183.             yoff += ((getSize().height - border * 2)
  184.                  - ((Ymax - Ymin) * xscale)) / 2;
  185.             yscale = xscale;
  186.         } else if (yscale < xscale) {
  187.             xoff += ((getSize().width - border * 2)
  188.                  - ((Xmax - Xmin) * yscale)) / 2;
  189.             xscale = yscale;
  190.         }
  191.         }
  192.         turtle = new CLSTurtle(startAngle, 0 - Xmin, 0 - Ymin,
  193.                    xoff, yoff, xscale, yscale);
  194.     }
  195.  
  196.     for (int pos = 0; pos < path.length(); pos++) {
  197.         switch (path.charAt(pos)) {
  198.         case '+':
  199.         turtle.rotate(rotAngle);
  200.         break;
  201.         case '-':
  202.         turtle.rotate(-rotAngle);
  203.         break;
  204.         case '[':
  205.         turtleStack.push(turtle);
  206.         turtle = new CLSTurtle(turtle);
  207.         break;
  208.         case ']':
  209.         turtle = (CLSTurtle) turtleStack.pop();
  210.         break;
  211.         case 'f':
  212.         turtle.jump();
  213.         break;
  214.         case 'F':
  215.         if (g == null) {
  216.             includePt(turtle.X, turtle.Y);
  217.             turtle.jump();
  218.             includePt(turtle.X, turtle.Y);
  219.         } else {
  220.             turtle.draw(g);
  221.         }
  222.         break;
  223.         default:
  224.         break;
  225.         }
  226.     }
  227.     }
  228.  
  229.     void includePt(float x, float y) {
  230.     if (x < Xmin)
  231.         Xmin = x;
  232.     if (x > Xmax)
  233.         Xmax = x;
  234.     if (y < Ymin)
  235.         Ymin = y;
  236.     if (y > Ymax)
  237.         Ymax = y;
  238.     }
  239.   
  240.   public String getAppletInfo() {
  241.     return "Title: CLSFractal 1.1f, 27 Mar 1995 \nAuthor: Jim Graham \nA (not yet) Context Sensitive L-System production rule. \nThis class encapsulates a production rule for a Context Sensitive\n L-System \n(pred, succ, lContext, rContext).  The matches() method, however, does not \n(yet) verify the lContext and rContext parts of the rule.";
  242.   }
  243.   
  244.   public String[][] getParameterInfo() {
  245.     String[][] info = {
  246.       {"level", "int", "Maximum number of recursions.  Default is 1."},
  247.       {"incremental","boolean","Whether or not to repaint between recursions.  Default is true."},
  248.       {"delay","integer","Sets delay between repaints.  Default is 50."},
  249.       {"startAngle","float","Sets the starting angle.  Default is 0."},
  250.       {"rotAngle","float","Sets the rotation angle.  Default is 45."},
  251.       {"border","integer","Width of border.  Default is 2."},
  252.       {"normalizeScale","boolean","Whether or not to normalize the scaling.  Default is true."},
  253.       {"pred","String","Initializes the rules for Context Sensitive L-Systems."},
  254.       {"succ","String","Initializes the rules for Context Sensitive L-Systems."},
  255.       {"lContext","String","Initializes the rules for Context Sensitive L-Systems."},
  256.       {"rContext","String","Initializes the rules for Context Sensitive L-Systems."}
  257.     };
  258.     return info;
  259.   }
  260. }
  261.  
  262. /**
  263.  * A Logo turtle class designed to support Context sensitive L-Systems.
  264.  *
  265.  * This turtle performs a few basic maneuvers needed to support the
  266.  * set of characters used in Context sensitive L-Systems "+-fF[]".
  267.  *
  268.  * @author     Jim Graham
  269.  * @version     1.1f, 27 Mar 1995
  270.  */
  271. class CLSTurtle {
  272.     float angle;
  273.     float X;
  274.     float Y;
  275.     float scaleX;
  276.     float scaleY;
  277.     int xoff;
  278.     int yoff;
  279.  
  280.     public CLSTurtle(float ang, float x, float y,
  281.              int xorg, int yorg, float sx, float sy) {
  282.     angle = ang;
  283.     scaleX = sx;
  284.     scaleY = sy;
  285.     X = x * sx;
  286.     Y = y * sy;
  287.     xoff = xorg;
  288.     yoff = yorg;
  289.     }
  290.  
  291.     public CLSTurtle(CLSTurtle turtle) {
  292.     angle = turtle.angle;
  293.     X = turtle.X;
  294.     Y = turtle.Y;
  295.     scaleX = turtle.scaleX;
  296.     scaleY = turtle.scaleY;
  297.     xoff = turtle.xoff;
  298.     yoff = turtle.yoff;
  299.     }
  300.  
  301.     public void rotate(float theta) {
  302.     angle += theta;
  303.     }
  304.  
  305.     public void jump() {
  306.     X += (float) Math.cos(angle) * scaleX;
  307.     Y += (float) Math.sin(angle) * scaleY;
  308.     }
  309.  
  310.     public void draw(Graphics g) {
  311.     float x = X + (float) Math.cos(angle) * scaleX;
  312.     float y = Y + (float) Math.sin(angle) * scaleY;
  313.     g.drawLine((int) X + xoff, (int) Y + yoff,
  314.            (int) x + xoff, (int) y + yoff);
  315.     X = x;
  316.     Y = y;
  317.     }
  318. }
  319.  
  320. /**
  321.  * A (non-)Context sensitive L-System class.
  322.  *
  323.  * This class initializes the rules for Context sensitive L-Systems
  324.  * (pred, succ, lContext, rContext) from the given java.applet.Applet's attributes.
  325.  * The generate() method, however, does not (yet) apply the lContext
  326.  * and rContext parts of the rules.
  327.  *
  328.  * @author     Jim Graham
  329.  * @version     1.1f, 27 Mar 1995
  330.  */
  331. class ContextLSystem {
  332.     String axiom;
  333.     Vector rules = new Vector();
  334.     int level;
  335.  
  336.     public ContextLSystem(java.applet.Applet app) {
  337.     axiom = app.getParameter("axiom");
  338.     int num = 1;
  339.     while (true) {
  340.         String pred = app.getParameter("pred"+num);
  341.         String succ = app.getParameter("succ"+num);
  342.         if (pred == null || succ == null) {
  343.         break;
  344.         }
  345.         rules.addElement(new CLSRule(pred, succ,
  346.                      app.getParameter("lContext"+num),
  347.                      app.getParameter("rContext"+num)));
  348.         num++;
  349.     }
  350.     currentPath = new StringBuffer(axiom);
  351.     level = 0;
  352.     }
  353.  
  354.     public int getLevel() {
  355.     return level;
  356.     }
  357.  
  358.     StringBuffer currentPath;
  359.  
  360.     public synchronized String getPath() {
  361.     return ((currentPath == null) ? null : currentPath.toString());
  362.     }
  363.  
  364.     private synchronized void setPath(StringBuffer path) {
  365.     currentPath = path;
  366.     level++;
  367.     }
  368.  
  369.     public void generate() {
  370.     StringBuffer newPath = new StringBuffer();
  371.     int pos = 0;
  372.     while (pos < currentPath.length()) {
  373.         CLSRule rule = findRule(pos);
  374.         if (rule == null) {
  375.         newPath.append(currentPath.charAt(pos));
  376.         pos++;
  377.         } else {
  378.         newPath.append(rule.succ);
  379.         pos += rule.pred.length();
  380.         }
  381.     }
  382.     setPath(newPath);
  383.     }
  384.  
  385.     public CLSRule findRule(int pos) {
  386.     for (int i = 0; i < rules.size(); i++) {
  387.         CLSRule rule = (CLSRule) rules.elementAt(i);
  388.         if (rule.matches(currentPath, pos)) {
  389.         return rule;
  390.         }
  391.     }
  392.     return null;
  393.     }
  394. }
  395.  
  396. /**
  397.  * A Context sensitive L-System production rule.
  398.  *
  399.  * This class encapsulates a production rule for a Context sensitive
  400.  * L-System (pred, succ, lContext, rContext).
  401.  * The matches() method, however, does not (yet) verify the lContext
  402.  * and rContext parts of the rule.
  403.  *
  404.  * @author     Jim Graham
  405.  * @version     1.1f, 27 Mar 1995
  406.  */
  407. class CLSRule {
  408.     String pred;
  409.     String succ;
  410.     String lContext;
  411.     String rContext;
  412.  
  413.     public CLSRule(String p, String d, String l, String r) {
  414.     pred = p;
  415.     succ = d;
  416.     lContext = l;
  417.     rContext = r;
  418.     }
  419.  
  420.     public boolean matches(StringBuffer sb, int pos) {
  421.     if (pos + pred.length() > sb.length()) {
  422.         return false;
  423.     }
  424.     char cb[] = new char[pred.length()];
  425.     sb.getChars(pos, pos + pred.length(), cb, 0);
  426.     return pred.equals(new String(cb));
  427.     }
  428. }
  429.